package com.goldsprite.gameframeworks.ecs;

import com.goldsprite.gameframeworks.ecs.component.IComponent;
import com.goldsprite.gameframeworks.ecs.entity.GObject;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import com.goldsprite.gameframeworks.ecs.component.*;

public class ComponentManager {
	private static int nextComponentId = 0;
	private static final Map<Class<? extends IComponent>, Integer> componentIds = new ConcurrentHashMap<>();
	private static final Map<Class<? extends IComponent>, List<IComponent>> componentPools = new ConcurrentHashMap<>();
	private static final Map<BitSet, List<GObject>> entityCache = new ConcurrentHashMap<>();
	private static final Map<GObject, BitSet> entityComponentMasks = new ConcurrentHashMap<>();

	public static <T extends IComponent> int preRegisterComponentType(Class<T> componentType) {
		return componentIds.computeIfAbsent(componentType, k -> nextComponentId++);
	}

	public static <T extends IComponent> int getComponentId(Class<T> componentType) {
		for(Class component : componentIds.keySet()) {
			if (componentType.equals(component)) continue;
			if(component.isAssignableFrom(componentType)) {
				componentType = component;
				break;
			}
		}
		return componentIds.computeIfAbsent(componentType, k -> nextComponentId++);
	}

	public static <T extends IComponent> void registerComponent(GObject entity, Class<T> componentType, IComponent component) {
		// 注册到组件池
		List<IComponent> pool = componentPools.computeIfAbsent(componentType, k -> new CopyOnWriteArrayList<>());
		if (!pool.contains(component)) {
			pool.add(component);
		}

		// 更新实体组件掩码
		BitSet mask = entityComponentMasks.computeIfAbsent(entity, k -> new BitSet());
		mask.set(getComponentId(componentType));

		// 清除缓存
		entityCache.clear();
	}

	public static <T extends IComponent> void unregisterComponent(GObject entity, Class<T> componentType, IComponent component) {
		// 从组件池移除
		List<IComponent> pool = componentPools.get(componentType);
		if (pool != null) {
			pool.remove(component);
		}

		// 更新实体组件掩码
		BitSet mask = entityComponentMasks.get(entity);
		if (mask != null) {
			mask.clear(getComponentId(componentType));
			if (mask.isEmpty()) {
				entityComponentMasks.remove(entity);
			}
		}

		// 清除缓存
		entityCache.clear();
	}

	public static <T extends IComponent> List<T> getComponents(Class<T> componentType) {
		List<IComponent> pool = componentPools.get(componentType);
		if (pool != null) {
			return new ArrayList<>((List<T>) pool);
		}
		return new ArrayList<>();
	}

	public static List<GObject> getEntitiesWithComponents(Class<? extends IComponent>... componentTypes) {
		if (componentTypes.length == 0) {
			return new ArrayList<>(entityComponentMasks.keySet());
		}

		BitSet queryMask = createComponentMask(componentTypes);

		// 检查缓存
		if (entityCache.containsKey(queryMask)) {
			return new ArrayList<>(entityCache.get(queryMask));
		}

		// 查询符合条件的实体
		List<GObject> result = new ArrayList<>();
		for (Map.Entry<GObject, BitSet> entry : entityComponentMasks.entrySet()) {
			BitSet entityMask = entry.getValue();
			if (containsAllRequiredComponents(entityMask, queryMask)) {
				result.add(entry.getKey());
			}
		}

		// 缓存结果
		entityCache.put(queryMask, new CopyOnWriteArrayList<>(result));
		return result;
	}

	private static BitSet createComponentMask(Class<? extends IComponent>... componentTypes) {
		BitSet mask = new BitSet();
		for (Class<? extends IComponent> type : componentTypes) {
			mask.set(getComponentId(type));
		}
		return mask;
	}

	private static boolean containsAllBits(BitSet source, BitSet target) {
		BitSet temp = (BitSet) target.clone();
		temp.and(source);
		return temp.equals(target);
	}

	/**
	 * 检查实体是否包含查询所需的所有组件（支持向上转型）
	 */
	private static boolean containsAllRequiredComponents(BitSet entityMask, BitSet queryMask) {
		// 对于查询掩码中的每个设置位，检查实体是否有对应的兼容类型
		for (int i = queryMask.nextSetBit(0); i >= 0; i = queryMask.nextSetBit(i + 1)) {
			Class<? extends IComponent> queryType = getTypeById(i);
			if (queryType == null) continue;

			boolean hasCompatible = false;

			// 检查实体是否有该查询类型或其子类型
			for (int j = entityMask.nextSetBit(0); j >= 0; j = entityMask.nextSetBit(j + 1)) {
				Class<? extends IComponent> entityType = getTypeById(j);
				if (entityType != null && queryType.isAssignableFrom(entityType)) {
					hasCompatible = true;
					break;
				}
			}

			if (!hasCompatible) {
				return false;
			}
		}

		return true;
	}
	/**
	 * 根据组件ID获取组件类型
	 */
	private static Class<? extends IComponent> getTypeById(int id) {
		for (Map.Entry<Class<? extends IComponent>, Integer> entry : componentIds.entrySet()) {
			if (entry.getValue() == id) {
				return entry.getKey();
			}
		}
		return null;
	}

	public static void updateEntityComponentMask(GObject entity) {
		// 重新计算实体的组件掩码
		BitSet mask = new BitSet();
		for (List<IComponent> components : entity.getComponents().values()) {
			for (IComponent comp : components) {
				mask.set(getComponentId(comp.getClass()));
			}
		}

		if (!mask.isEmpty()) {
			entityComponentMasks.put(entity, mask);
		} else {
			entityComponentMasks.remove(entity);
		}

		entityCache.clear();
	}

	public static void removeEntity(GObject entity) {
		// 从所有组件池中移除该实体的组件
		for (List<IComponent> components : entity.getComponents().values()) {
			for (IComponent comp : components) {
				for (List<IComponent> pool : componentPools.values()) {
					pool.remove(comp);
				}
			}
		}

		entityComponentMasks.remove(entity);
		entityCache.clear();
	}

	public static void clearCache() {
		entityCache.clear();
	}

	public static int getRegisteredComponentCount() {
		return componentPools.size();
	}

	public static int getTotalEntityCount() {
		return entityComponentMasks.size();
	}

	public static void debugInfo() {
		System.out.println("=== IComponent Manager Debug Info ===");
		System.out.println("Registered IComponent Types: " + componentIds.size());
		System.out.println("Total Entities: " + getTotalEntityCount());
		System.out.println("Cached Queries: " + entityCache.size());

		for (Map.Entry<Class<? extends IComponent>, Integer> entry : componentIds.entrySet()) {
			List<IComponent> pool = componentPools.get(entry.getKey());
			int count = pool != null ? pool.size() : 0;
			System.out.println("  " + entry.getKey().getSimpleName() + " (ID: " + entry.getValue() + "): " + count + " instances");
		}
	}
}
